<script setup lang="ts">
import {onMounted, onUnmounted, reactive, ref, watch} from "vue";
import codeImg from "@/static/image/codeImg.jpg"

import {Message, Spin} from "view-ui-plus"
import {useStore} from "vuex";
import QRCode from 'qrcode'
import {Login} from "@/api/index"
import {qqCallBackUrl} from "@/plugins/config.ts"
import {useRouter} from "vue-router";


type Axis = {
  x: number,  // 记录 X 坐标轴
  y: number,  // 记录 Y 坐标轴
  blockX?: any  // 拖动控件已移动的距离
}

declare const QC;

const router = useRouter();

const validateVerify = (rule: any, value: any, callback: any) => {
  if (verify.value) {
    callback();
  } else {
    callback(new Error('请先拖动滑块进行安全验证'));
  }
};

const formValidate = ref<any>(null);

const loginFrom = ref({
  username: "",
  password: ""
})

const ruleValidate = ref({
  username: [
    {required: true, message: '请输入用户名/邮箱', trigger: 'blur'},
    {required: true, type: 'string', min: 4, message: '用户名最低字符为4位', trigger: 'blur'},
    {required: true, type: 'string', max: 30, message: '超过最大字符数量', trigger: 'blur'}
  ],
  password: [
    {required: true, message: '请输入密码', trigger: 'blur'},
    {required: true, type: 'string', min: 8, message: '密码最低字符为8位', trigger: 'blur'},
    {required: true, type: 'string', max: 30, message: '超过最大字符数量', trigger: 'blur'}
  ],
  verify: [
    {validator: validateVerify, trigger: 'blur'}
  ]
})

let store = useStore();

let show = ref(false);  // 控制验证码窗口的显示
let timer = ref<any>(null);
let press = ref(false); // 当前拖动条是否按下
let block = ref<any>(null); // 拖动滑块控件
let startAxis = reactive<Axis>({x: 0, y: 0, blockX: 0});  // 鼠标按下时的坐标轴
let endAxis = reactive<Axis>({x: 0, y: 0}); // 鼠标抬起时的坐标轴
let Axis = reactive({x: 0, y: 0});  // 验证码拼图随机的坐标轴
let errorVal = ref(2);  // 校验误差值
let verify = ref(false); // 校验结果 如果为真将无法再使用拼图
let CutImg = ref(true); // 切换二维码和账号登录
let qrCodeImg = ref('');  // 二维码图片地址

const onMouseover = function () {
  // 鼠标移入拖到控件事件
  if (!verify.value) {
    clearTimeout(timer.value);
    show.value = true;
  }
}
const onMouseout = function () {
  // 鼠标移出拖动控件事件
  if (!verify.value) {
    clearTimeout(timer.value);
    timer.value = setTimeout(() => {
      show.value = false;
      // 500毫秒再次进入可防止关闭弹窗
    }, 500)
  }
}


const onMousedown = function (e: any) {
  // 鼠标在拖动条控件按下事件
  // console.log(e,'onMousedown======')
  clearTimeout(timer.value);
  show.value = true;
  // 以免鼠标在离开拖动条时关闭弹窗
  if (e.type == "touchstart") {
    let touch = e.targetTouches[0];
    startAxis = {
      x: touch.clientX,
      y: touch.clientY,
      blockX: block.value.offsetLeft
    }
  } else {
    startAxis = {
      x: e.clientX,
      y: e.clientY,
      blockX: block.value.offsetLeft
    }
  }

  // 记录按下时的坐标轴 blockX 为拖到控件已移动的距离
  press.value = true;
  // 为真表示点击拖动条拖拽中
}

const onMousemove = (e: any) => {
  // console.log(e,'onMousemove')
  if (press.value) {
    clearTimeout(timer.value);
    show.value = true;
    // console.log(e, "鼠标移动了")
    // console.log([block.value], 'block.value')
    if (e.type === 'touchmove') {
      let touch = e.targetTouches[0];
      endAxis = {
        x: touch.clientX,
        y: touch.clientY
      }
    } else {
      endAxis = {
        x: e.clientX,
        y: e.clientY
      }
    }


    let scroll: any = document.getElementById("scroll");

    // console.log(endAxis.x , startAxis.x , startAxis.blockX)

    if (endAxis.x > startAxis.x) {
      // 左往右 >>>>>>>>>>
      let moveX: number = endAxis.x - startAxis.x + startAxis.blockX;

      // console.log(`移动距离 ---- ${moveX}`);

      if (moveX <= 340 - block.value.offsetWidth) {
        // 移动滑块
        block.value.style.left = moveX + 'px';
        scroll.style.left = (moveX + 5) + 'px';
      }
    } else {
      // 右往左 <<<<<<<<<<
      let moveX: number = startAxis.blockX - (startAxis.x - endAxis.x);
      // console.log(`移动距离 ---- ${moveX}`);
      if (moveX >= 0) {
        block.value.style.left = moveX + 'px';
        scroll.style.left = (moveX + 5) + 'px';
      }
    }
    // console.log(startAxis, endAxis)

  }
}

const onMouseup = () => {
  if (show.value) {
    press.value = false;
    let scroll: any = document.getElementById("scroll");
    if (Axis.x <= (scroll.offsetLeft + errorVal.value) && Axis.x >= (scroll.offsetLeft - errorVal.value)) {
      clearTimeout(timer.value);
      show.value = false;
      verify.value = true;  // 验证成功 关闭弹窗
    } else {
      console.log("验证失败");
      block.value.style.left = 0;
      scroll.style.left = 5 + 'px';
      init();
    }
  }
}

function init(clear: boolean = false) {
  // 验证码拼图初始化
  let x = 50;
  let y = 92;
  let width = 30;
  let radius = 6; //半径

  x = Math.floor(Math.random() * (340 - width * 4) + width * 2);
  y = Math.floor(Math.random() * (180 - width * 3) + width);

  Axis = {x, y};  // 拼图的（x,y）坐标轴

  let canvas: any = document.getElementById("canvas");
  let scroll: any = document.getElementById("scroll");
  // let range : any = document.getElementById("range");

  // range.max = (340 - (width + radius + 10));
  canvas.width = 340;
  canvas.height = 180;
  scroll.width = 340;
  scroll.height = 180;

  let ctx = canvas.getContext('2d');
  let ctx2 = scroll.getContext('2d');

  if (clear) {
    ctx.clearRect(0, 0, 340, 180)
  }

  let img = new Image(); //创建图片对象
  img.crossOrigin = "anonymous";
  path(false)
  path(true)
  img.onload = function () {
    ctx.drawImage(img, 0, 0, 340, 180);
    ctx2.drawImage(img, 0, 0, 340, 180);
    console.log(x, y, '移动的距离');
    let imgs = ctx2.getImageData(x, y, width + radius, width + radius)
    scroll.width = width + radius;
    ctx2.putImageData(imgs, 0, y)
  }

  img.src = codeImg;

  function path(status: boolean) {
    //绘制图形
    if (!status) {
      ctx.beginPath(); //新建一条path
      ctx.lineWidth = 1;
      ctx.fillStyle = 'rgba(255,255,255,1)';
      ctx.strokeStyle = 'rgba(255,255,255,1)';
      ctx.moveTo(x, y);
      ctx.lineTo(x + width, y);
      ctx.arc(x + width, (width / 2) + y, radius, (Math.PI / 180) * -90, (Math.PI / 180) * 90);
      ctx.lineTo(x + width, y + width);
      ctx.arc(x + (width / 2), y + width, radius, (Math.PI / 180) * 0, (Math.PI / 180) * 180);
      ctx.lineTo(x, y + width);
      ctx.arc(x, (width / 2) + y, radius, (Math.PI / 180) * 90, (Math.PI / 180) * -90, true);
      ctx.lineTo(x, y);
      ctx.stroke()
      ctx.globalCompositeOperation = 'destination-over';
      ctx.fill()
    } else {
      ctx2.beginPath(); //新建一条path
      ctx2.lineWidth = 1;
      ctx2.fillStyle = 'rgba(255,255,255,0)';
      ctx2.strokeStyle = 'rgba(255,255,255,0.5)';
      ctx2.moveTo(x, y);
      ctx2.lineTo(x + width, y);
      ctx2.arc(x + width, (width / 2) + y, radius, (Math.PI / 180) * -90, (Math.PI / 180) * 90);
      ctx2.lineTo(x + width, y + width);
      ctx2.arc(x + (width / 2), y + width, radius, (Math.PI / 180) * 0, (Math.PI / 180) * 180);
      ctx2.lineTo(x, y + width);
      ctx2.arc(x, (width / 2) + y, radius, (Math.PI / 180) * 90, (Math.PI / 180) * -90, true);
      ctx2.lineTo(x, y);
      ctx2.closePath();
      ctx2.stroke();
      ctx2.globalCompositeOperation = 'destination-over';
      ctx2.clip();
    }
  }
}

const onLogin = () => {
  // 登录
  formValidate.value.validate((valid: boolean) => {
    // 验证
    if (valid) {
      Spin.show({
        render: (h) => {
          return h('div', [
            h('i', {
              'class': 'ivu-icon ivu-icon-ios-loading demo-spin-icon-load',
              'style': {
                'font-size': '22px'
              }
            }),
            h('div', '登录中')
          ])
        }
      });
      Login(loginFrom.value).then((res: any) => {
        console.log(res);
        if (res.code == 200) {
          Message.success(res.message)
          store.dispatch('UpdateLoginStatus', {
            Token: res.data.token,
            UserData: res.data.userInfo
          })
          setTimeout(() => {
            Spin.hide();
            router.replace('/');
          }, 800)
        } else {
          Spin.hide();
          Message.error(res.message)
        }

      }).catch(() => Spin.hide())

    }
  })
}

const getCode = async () => {
  const text = "二维码登录功能暂未开放"
  // qrCodeImg.value = await QRCode.toDataURL(text);
  // console.log(qrCodeImg.value);
  // 跳转网页
  QRCode.toDataURL('https://blog.wzhyt.cn/error.html')
      .then(url => {
        console.log(url)
        qrCodeImg.value = url;
      })
      .catch(err => {
        console.error(err)
      })
}

const qqLogin = () => {
  // QQ登录
  const qqLoginUrl = 'https://graph.qq.com/oauth2.0/authorize?client_id=' + QC.getAppId() + '&response_type=token&redirect_uri=' + qqCallBackUrl
  location.href = qqLoginUrl;

}

watch(CutImg, (newValue, oldValue) => {
  if (!newValue) {
    getCode()
  }
});


onUnmounted(() => {
  // 卸载监听事件
  window.removeEventListener('mousemove', onMousemove);
  window.removeEventListener('mouseup', onMouseup);

  window.removeEventListener('touchmove', onMousemove);
  window.removeEventListener('touchend', onMouseup);
})

onMounted(() => {
  // 页面载入
  window.addEventListener('mousemove', onMousemove);
  window.addEventListener('mouseup', onMouseup);

  window.addEventListener('touchmove', onMousemove);
  window.addEventListener('touchend', onMouseup);
  // 验证码初始化
  init();
  // 生成验证码
})
</script>

<template>
  <div class="loginBack">
    <div class="title" @click="router.push('/')">首页</div>
    <div class="loginWIn">
      <div class="loginCutDiv" @click="CutImg=!CutImg">
        <img v-show="CutImg" src="@/static/image/qrcode.png" alt="">
        <img v-show="!CutImg" src="@/static/image/computer.png" alt="">
      </div>
      <div v-show="CutImg">
        <div class="loginTitle">
          用户名登录
        </div>
        <Form ref="formValidate" :model="loginFrom" :rules="ruleValidate" label-position="top">
          <FormItem prop="username">
            <Input size="large" element-id="login.username" autocomplete="off" v-model="loginFrom.username"
                   placeholder="用户名/邮箱"/>
          </FormItem>
          <FormItem prop="password">
            <Input size="large" element-id="login.password" autocomplete="off" type="password" password
                   v-model="loginFrom.password" placeholder="密码"/>
          </FormItem>
          <FormItem prop="verify">
            <div class="loginFrom">
              <div class="canvas_div" @mouseover="onMouseover" @mouseout="onMouseout" @touchmove="onMouseover"
                   @touchend="onMouseout" v-show="show">
                <canvas class="scroll" id="scroll"></canvas>
                <canvas class="canvas" id="canvas"></canvas>
                <Icon type="md-refresh" @click="init" class="refresh"/>
              </div>
              <div class="range_div" :class="{verify:verify}" @mouseover="onMouseover" @mouseout="onMouseout"
                   @touchmove="onMouseover" @touchend="onMouseout">
                <div class="range_scroll" v-show="!verify" ref="block" @mousedown="onMousedown"
                     @touchstart="onMousedown">→
                </div>
                <div class="hint" v-show="!verify && !press">向右拖动滑块填充拼图</div>
                <div class="verifyText" v-show="verify">验证成功</div>

                <!--          <input class="range" id="range" type="range" min="0" max="100" step="1" value="0" oninput="updateValue(this.value)" onchange="change(this.value)">-->
              </div>
            </div>
          </FormItem>
          <Button size="large" type="primary" style="width: 100%;" @click="onLogin">登录</Button>
          <div class="restForm">
            <div class="aboutUser">
              <span>还没有账号?</span>
              <span>找回密码</span>
            </div>
            <div class="loginAbout">
              <span>其他登录方式</span>
            </div>
            <div class="loginList">
              <div class="loginItem" @click="qqLogin">
                <img src="@/static/image/qq.png" alt="">
              </div>
            </div>
          </div>
        </Form>
      </div>
      <div v-show="!CutImg">
        <div class="loginTitle">
          扫码登录
        </div>
        <p style="text-align: center">二维码登录功能暂未开放</p>
        <div class="qrCodeDiv">
          <img class="qrCodeImg" :src="qrCodeImg" alt="">
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.loginBack {
  > .title {
    font-size: 30px;
    font-weight: 400;
    position: absolute;
    left: 150px;
    top: 20px;
    cursor: pointer;
  }

  .loginWIn {
    width: 460px;
    height: 520px;
    background: #fff;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    border-radius: 8px;
    box-shadow: 0 0 18px 0 rgba(57, 141, 238, 0.12);
    padding: 30px 60px;

    .loginCutDiv {
      position: absolute;
      right: 6px;
      top: 6px;
      width: 55px;
      height: 55px;
      background-color: rgba(101, 173, 106, 1);
      border-radius: 0 8px 0 0;
      clip-path: polygon(0 0, 100% 0, 100% 100%, 0 0);
      padding: 4px;
      display: flex;
      justify-content: end;
      cursor: pointer;

      > img {
        width: 35px;
        height: 35px;
      }
    }

    .loginTitle {
      padding: 30px 0 50px;
      font-size: 24px;
      font-weight: 500;
      color: #333;
    }

    .qrCodeDiv {
      display: flex;
      width: 100%;
      justify-content: center;
      padding: 20px 0;

      .qrCodeImg {
        width: 200px;
        height: 200px;
      }
    }


    .loginFrom {
      position: relative;
      margin-top: 5px;
    }

    .restForm {
      .aboutUser {
        display: flex;
        justify-content: space-between;
        padding: 10px 0;
      }

      .loginAbout {
        text-align: center;
        font-size: 12px;
        position: relative;

        span {
          background-color: #fff;
          position: relative;
          z-index: 2;
          padding: 0 10px;
          color: #999;
        }

        &:after {
          content: "";
          z-index: 1;
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          left: 0;
          right: 0;
          height: 1px;
          background: #ddd;
        }
      }

      .loginList {
        display: flex;
        justify-content: center;
        padding: 20px 0;

        .loginItem {
          width: 35px;
          height: 35px;
          border-radius: 50%;
          background-color: #eee;
          display: flex;
          align-items: center;
          justify-content: center;
          cursor: pointer;

          img {
            width: auto;
            height: 20px;
          }
        }
      }
    }

  }
}

.canvas_div {
  height: 180px;
  border-radius: 12px;
  position: fixed;
  transform: translateY(-100%);
  z-index: 20;

  .refresh {
    position: absolute;
    right: 10px;
    top: 10px;
    z-index: 21;
    cursor: pointer;
    font-size: 25px;
    transition: all 0.1s;

    &:hover {
      font-size: 26px;
    }
  }
}

.canvas {
  width: 340px;
  height: 180px;
  position: relative;
  z-index: 9;
  border-radius: 4px;
}

.scroll {
  position: absolute;
  left: 5px;
  top: 0;
  z-index: 10;
}

.range_div {
  width: 100%;
  height: 40px;
  border: 1px solid #e4e7eb;
  background-color: #f7f9fa;
  border-radius: 4px;
  display: flex;
  align-items: center;

  &.verify {
    border: 1px solid #65ad6a;
    background-color: rgba(101, 173, 106, .1);

    .verifyText {
      color: #65ad6a;
      user-select: none;
      margin: 0 auto;
    }
  }

  .range_scroll {
    position: absolute;
    width: 40px;
    height: 40px;
    background-color: #fff;
    box-shadow: 0 0 3px rgba(0, 0, 0, .3);
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    font-weight: 500;
    user-select: none;

    &:active {
      box-shadow: 0 0 3px rgba(101, 173, 106, .9);
      background-color: rgba(101, 173, 106, 1);
      color: #fff;
    }
  }


  .hint {
    margin: 0 auto;
    user-select: none;
  }
}

.range {
  width: 100%;
}

.reset {
  outline: none;
  padding: 5px 15px;
  border: none;
  background-color: cadetblue;
  color: #fff;
  border-radius: 3px;
  margin: 20px 0;
}
</style>
<style>
.demo-spin-icon-load {
  animation: ani-demo-spin 1s linear infinite;
}

@keyframes ani-demo-spin {
  from {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(180deg);
  }
  to {
    transform: rotate(360deg);
  }
}
</style>
